﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace Sofire.Data
{
    public partial class QueryEngineBase
    {
        internal ReaderResult ExecuteReader(DbConnection connection, DbTransaction transaction, ExecuteReaderHandler rd, ExecuteCommand command, bool autoClosed)
        {
            Exception exception = null;
            DbDataReader reader = null;
            DbCommand dbCommand = this.CreateCommand(connection, command);

            if(transaction != null) dbCommand.Transaction = transaction;
            command.Aborted = false;
            var userToken = this.OnExecuting(ExecuteType.Reader, command);
            try
            {
                if(connection.State == ConnectionState.Closed) connection.Open();
                using(reader = dbCommand.ExecuteReader())
                {
                    /*
                     * ExecuteReader((reader)=>
                     * {
                     *      while(reader.Read()){
                     *          reader.GetString(0);//返回 0列 的字符串数据
                     *      };
                     * },"SELECT * FROM TABLE1");
                     */
                    rd(reader);
                }
            }

            catch(Exception ex)
            {
                if(command.Aborted)
                {
                    exception = ExecuteAbortException.Instance;
                }
                else
                {
                    exception = ex;
                }
            }
            finally
            {
                if(autoClosed) connection.TryClose();
            }
            var r = new ReaderResult();

            r.Initialization(this, dbCommand, false, exception);

            this.OnExecuted(ExecuteType.Reader, r, command, userToken);

            return r;
        }

        internal ReaderResult<TResultValue> ExecuteReader<TResultValue>(DbConnection connection, DbTransaction transaction, ExecuteReaderHandler<TResultValue> rd, ExecuteCommand command, bool autoClosed)
        {
            Exception exception = null;
            DbDataReader reader = null;
            TResultValue result = default(TResultValue);
            DbCommand dbCommand = this.CreateCommand(connection, command);
            if(transaction != null) dbCommand.Transaction = transaction;
            command.Aborted = false;
            var userToken = this.OnExecuting(ExecuteType.Reader, command);
            try
            {
                if(connection.State == ConnectionState.Closed) connection.Open();
                using(reader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    result = rd(reader);
                }
            }
            catch(Exception ex)
            {
                if(command.Aborted)
                {
                    exception = ExecuteAbortException.Instance;
                }
                else
                {
                    exception = ex;
                }
            }
            finally
            {
                if(autoClosed) connection.TryClose();
            }
            var r = new ReaderResult<TResultValue>();
            r.Initialization(this, dbCommand, result, exception);

            this.OnExecuted(ExecuteType.Reader, r, command, userToken);

            return r;
        }

        internal Result<TModel> ExecuteModelByReader<TModel>(DbConnection connection, ExecuteCommand command)
            where TModel : class ,IModelLoadable, new()
        {
            Result<TModel> result = null;

            var r = this.ExecuteReader(connection, null, (reader) =>
            {
                result = new Result<TModel>();
                if(!reader.Read()) return;
                var model = new TModel();
                if(model.Load(reader))
                    result.ToSuccessed(model);
            }, command, true);
            if(r.IsFailed) return r.Exception;
            return result;
        }

        internal Result<List<TModel>> ExecuteModelsByReader<TModel>(DbConnection connection, ExecuteCommand command)
            where TModel : class ,IModelLoadable, new()
        {
            List<TModel> models = new List<TModel>();
            var r = this.ExecuteReader(connection, null, (reader) =>
            {
                if(!reader.Read()) return;
                var model = new TModel();
                if(model.Load(reader))
                    models.Add(model);
            }, command, true);
            if(r.IsFailed) return r.Exception;
            return models;
        }

        #region - ExecuteReader -

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="command">执行查询的命令。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, ExecuteCommand command)
        {
            return this.ExecuteReader(this.CreateConnection(), null, rd, command, true);
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, params object[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, object objectInstance)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }

        #endregion

        #region ExecuteReader<TResultValue>

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="command">执行查询的命令。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, ExecuteCommand command)
        {
            return this.ExecuteReader<TResultValue>(this.CreateConnection(), null, rd, command, true);
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, params object[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, object objectInstance)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }

        #endregion

    }

    public partial class QueryContext
    {

        #region - ExecuteReader -

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="command">执行查询的命令。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, ExecuteCommand command)
        {
            return this.Engine.ExecuteReader(this.Connection, this.Transaction, rd, command, false);
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, params object[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public ReaderResult ExecuteReader(ExecuteReaderHandler rd, string commandText, object objectInstance)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }

        #endregion

        #region - ExecuteReader<TResultValue> -

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="command">执行查询的命令。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, ExecuteCommand command)
        {
            return this.Engine.ExecuteReader<TResultValue>(this.Connection, this.Transaction, rd, command, false);
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, params object[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并构建一个读取器。
        /// </summary>
        /// <typeparam name="TResultValue">返回值的类型。</typeparam>
        /// <param name="rd">给定的读取器委托。</param>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public ReaderResult<TResultValue> ExecuteReader<TResultValue>(ExecuteReaderHandler<TResultValue> rd, string commandText, object objectInstance)
        {
            return this.ExecuteReader(rd, new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }

        #endregion

    }
}